#include "Piece.h"
#include "../Game/Engine.h"
#include "../Game/Player.h"
#include "../Game/Move.h"
#include "../Game/MoveTracker.h"
#include "../Board/Chessboard.h"
#include "../Board/Square.h"



namespace Core
{
	Piece::Piece(Player * player, Square * square)
		: _isEaten(false), _validMovesUpdateCount(-1)
	{
		if(player == NULL/* || square == NULL*/)
			throw "Piece.ctor: Argument cannot be NULL";

		_plr = player;
		_sq = square;
		//_sq->piece(this);

		_tracker = new MoveTracker();
	}

	Piece::~Piece()
	{
		this->deleteValidMoves();

		delete _tracker;
	}

	ChColor Piece::color() const 
	{ 
		return _plr->color(); 
	}

	int Piece::key() const
	{
		return (int)type() + (int)color() * 10;
	}

	Player * Piece::player() const 
	{ 
		return _plr; 
	}
	
	Square * Piece::square() const 
	{
		return _sq; 
	}
	
	void Piece::square(Square * val) 
	{
		_sq = val;
	}
	
	bool Piece::isEaten() const 
	{ 
		return _isEaten; 
	}
	
	void Piece::setEaten(bool val) 
	{ 
		_isEaten = val;
		//if(_isEaten)
		//	this->square()->piece(NULL);
	}
	
	bool Piece::validMovesExpired() const
	{
		return _validMovesUpdateCount != Engine::instance()->moveNumber();
	}

	void Piece::validMovesUpdated() 
	{
		_validMovesUpdateCount = Engine::instance()->moveNumber();

		map<int, Move*>::iterator it = _validMoves.begin();
		// consider check status
		while (it != _validMoves.end())
		{
			// analyze the move!
			ChStatus st = Engine::instance()->analyzeMove(it->second);
			// set move status
			it->second->status(st);
			//map<int, Move*>::iterator tmp = it++;

			if((this->color() == ChBlack && (st == ChStatus::ChBlackIsChecked || st == ChStatus::ChBlackIsCheckmate)) ||
				this->color() == ChWhite && (st == ChStatus::ChWhiteIsChecked || st == ChStatus::ChWhiteIsCheckmate))
			{
				delete it->second;
				_validMoves.erase(it++);
			}
			else
				++it;
		}
	}

	map<int, Move*> & Piece::validMoves()
	{
		if(this->validMovesExpired())
		{
			this->deleteValidMoves();
			this->updateValidMoves();
			this->validMovesUpdated();
		}

		return _validMoves;
	}
	
	void Piece::deleteValidMoves()
	{
		// delete valid moves
		for (map<int, Move*>::iterator it = _validMoves.begin(); it != _validMoves.end(); it++)
		{
			delete it->second;
		}

		_validMoves.clear();
		_validMovesUpdateCount = -1;
	}

	bool Piece::checkDestination(Move * mv) const
	{
		/*if(dst == NULL)
			return false;*/

		if(mv->to()->piece() == NULL)
			return true;
		if(mv->to()->piece()->color() == this->color())
			return false;
		if(mv->to()->piece()->type() != ChKing)
		{
			mv->action(mv->action() | ChEat);
			mv->pieceEaten(mv->to()->piece());
			return true;
		}
		// else (king)
		return false;
	}

	bool Piece::hasNotMovedYet() const
	{
		return _tracker->moveCount() == 0;
	}

	const Move * Piece::canMove(Square * dst)
	{
		
		if(this->validMoves().find(dst->key()) == _validMoves.end()) // cannot move
			return NULL;
		
		Move * mv = _validMoves.find(dst->key())->second;
		// consider check condition


		return mv;
	}

	void Piece::move(const Move& mv)
	{
		_tracker->newMove(mv); // validates and adds the move obj
		//this->square(mv.to());
	}

	void Piece::undoMove()
	{
		_tracker->undo();
	}

	void Piece::redoMove()
	{
		const Move * m = _tracker->at(_tracker->moveCount());
		if(m == NULL)
			return;
		_tracker->newMove(*m);
	}
}
